﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Midi;
using MIDIRemapper.DeviceInterfaces;
using MIDIRemapper.FileInterfaces;

namespace MIDIRemapper
{
    public partial class Form1 : Form
    {
        const int N_A = 1;
        DeviceInterface di = new DeviceInterface();
        FileInterface fi = new FileInterface();
        int selectedInput = -1;
        int selectedOutput = -1;

        public void DisplayStatus(string status)
        {
            statusLabel.Text = status;
        }

        private void RefreshRouteList()
        {
            List<Transformable> routes = di.GetTransformations();
            routeList.Items.Clear();
            foreach (Transformable route in routes)
            {
                routeList.Items.Add(route.ToString());
            }
            SelectDevices();
        }

        private void SelectDevices()
        {
            foreach (string o in inputsBox.Items.Cast<string>())
            {
                string s = o.Substring(o.IndexOf(':')+2, o.Length - o.IndexOf(':') - 2);
                if (s == di.inputDeviceName)
                {
                    inputsBox.SelectedItem = o;
                    break;
                }
            }
            foreach (string o in outputsBox.Items.Cast<string>())
            {
                string s = o.Substring(o.IndexOf(':') + 2, o.Length - o.IndexOf(':') - 2);
                if (s == di.outputDeviceName)
                {
                    outputsBox.SelectedItem = o;
                    break;
                }
            }
        }

        private void ShowRouteForm()
        {
            RouteForm rf = new RouteForm();
            DialogResult dr = rf.ShowDialog(this);

            if (dr == DialogResult.OK)
            {
                di.AddTransformation(rf.Result);

                routeList.Items.Add(rf.Result.ToString());

                DisplayStatus("Route added successfully.");
            }
        }

        #region Event Handlers

        private void Form1_Load(object sender, EventArgs e)
        {
            LoadDefaults();
        }

        private void LoadDefaults()
        {
            string inputName; string outputName;
            List<Transformable> routes;
            if (fi.LoadDefaultSettings(out inputName, out outputName, out routes))
            {
                StringBuilder report = new StringBuilder();
                di.LoadTransformations(routes);

                if (di.LoadInputDevice(inputName, out selectedInput))
                {
                    report.Append("Default input device loaded. ");
                }
                else
                {
                    report.Append("Default input device not available. ");
                    inputName = string.Empty;
                }
                if (di.LoadOutputDevice(outputName, out selectedOutput))
                {
                    report.Append("Default output device loaded. ");

                }
                else
                {
                    report.Append("Default output device not available. ");
                    outputName = string.Empty;
                }
                DisplayStatus(report.ToString());
                RefreshRouteList();
            }
            else
            {
                DisplayStatus("Default settings not available.");
            }

        }

        private void saveAsDefaultToolStripMenuItem_Click(object sender, EventArgs e)
        {
            new FileInterface().SaveDefaultSettings(di);
        }

        private void loadDefaultToolStripMenuItem_Click(object sender, EventArgs e)
        {
            LoadDefaults();
        }

        #region Device selection handlers
        private void inputsBox_Click(object sender, EventArgs e)
        {
            if (inputsBox.SelectedIndex != -1 && inputsBox.SelectedIndex != selectedInput)
            {
                try
                {
                    di.LoadInputDevice(inputsBox.SelectedIndex);
                    selectedInput = inputsBox.SelectedIndex;
                    di.UnloadInputDevice();
                }
                catch (DeviceException)
                {
                    DisplayStatus("Error loading input device.");
                    inputsBox.ClearSelected();
                }
            }
        }

        private void outputsBox_Click(object sender, EventArgs e)
        {
            if (outputsBox.SelectedIndex != -1 && outputsBox.SelectedIndex != selectedOutput)
            {
                try
                {
                    di.LoadOutputDevice(outputsBox.SelectedIndex);
                    selectedOutput = outputsBox.SelectedIndex;
                    di.UnloadOutputDevice();
                }
                catch (DeviceException)
                {
                    DisplayStatus("Error loading input device.");
                    outputsBox.ClearSelected();
                }
            }
        }

        private void inputsBox_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar == Environment.NewLine.ToCharArray()[0])
            {
                inputsBox_Click(sender, (EventArgs)e);
            }
        }
        private void outputsBox_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar == Environment.NewLine.ToCharArray()[0])
            {
                outputsBox_Click(sender, (EventArgs)e);
            }

        }

        private void refreshButton_Click(object sender, EventArgs e)
        {
            loadDeviceLists();
            SelectDevices();
        }

        private void unloadButton_Click(object sender, EventArgs e)
        {
            di.UnloadInputDevice();
            selectedInput = -1;
            inputsBox.ClearSelected();

            di.UnloadOutputDevice();
            selectedOutput = -1;
            outputsBox.ClearSelected();
            
            DisplayStatus("All MIDI devices unloaded.");
        }
        #endregion

        #region Routing selection handlers
        private void addRouteButton_Click(object sender, EventArgs e)
        {
            ShowRouteForm();
        }

        private void deleteToolStripMenuItem_Click(object sender, EventArgs e)
        {
            di.RemoveTransformation(routeList.SelectedIndex);
            routeList.Items.RemoveAt(routeList.SelectedIndex);
            DisplayStatus("Route successfully deleted.");
        }

        private void lists_MouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                ((ListBox)sender).Focus();
                //grey it out if the user has not selected an item
                deleteToolStripMenuItem.Enabled = ((ListBox)sender).SelectedItem == null ? false : true;
                rListsMenu.Show((ListBox)sender, e.Location);
            }
        }

        private void deleteRouteButton_Click(object sender, EventArgs e)
        {
            if (routeList.SelectedIndex >= 0)
            {
                di.RemoveTransformation(routeList.SelectedIndex);
                routeList.Items.RemoveAt(routeList.SelectedIndex);
                DisplayStatus("Route successfully deleted.");
            }
            else
            {
                DisplayStatus("No route selected.");
            }
        }
        #endregion

        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            MessageBox.Show(this, @"MIDI Rerouter by Aaron Campbell.

See midireroute.codeplex.com to check for newer editions, to report bugs, to suggest features, etc.

This project implements Tom Lokovic's midi-dot-net software. License agreement:

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS"" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.",
            "About MIDI Rerouter", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

        #endregion
    }
}
